package player;

import game.Camera;
import game.Level;

import java.awt.geom.Rectangle2D;
import java.io.File;

import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

import utility.Util;
import drawables.PlayerDrawable;

public class Player  {

	public static final int SPEED_STATIONARY = 0,
	SPEED_SLOW = 1,
	SPEED_FAST = 2;

	private boolean crouching = false;
	private boolean sprinting = false;
	private boolean dead = false;
	
	private float stamina = 0;
	private static float STAMINA_COST = 0.03f;
	private static float STAMINA_RECHARGE = 0.03f;

	private float x;
	private float y;

	private PlayerDrawable drawable;

	private float visibility = 0.0f;

	public Player(float x, float y) throws SlickException {
		this.x = x;
		this.y = y;
		drawable = new PlayerDrawable();
	}

	public float visibility(){
		if(sprinting) return 1.0f;
		return visibility;
	}

	public int speed(){
		//TODO based on previous movement
		return SPEED_STATIONARY;
	}

	public float sprintCharge(){
		return stamina;
	}

	//will be handled in PlayerDrawable
	public void draw(Graphics g, Camera camera) {
		drawable.draw(g, camera);
	}

	public Rectangle2D getBoundingBox(){
		return new Rectangle2D.Float(x-16, y-16, 32, 32);
	}

	public boolean crouching() {
		return crouching;
	}

	public boolean sprinting() {
		return sprinting;
	}

	public void setCrouch(boolean isCrouched) throws SlickException {
		if (crouching == isCrouched) {
			return; // no need to change state
		}
		// change crouch toggle if state has changed
		if (!crouching && isCrouched) {
			STEP = CROUCHING_STEP;
			crouching = true;
			sprinting = false;
		} else if (crouching && !isCrouched) {
			STEP = STANDARD_STEP;
			crouching = false;
		}
	}

	public void setSprint(boolean isSprinting) throws SlickException {
		if (sprinting == isSprinting) {
			return; // no need to change state
		}

		// change sprint toggle if state has changed
		if (isSprinting && stamina > 0.25f) {
			STEP = SPRINTING_STEP;
			crouching = false;
			sprinting = true;
		} else{
			STEP = STANDARD_STEP;
			sprinting = false;
		}
	}

	public void move(int inputX, int inputY, Level level) throws SlickException {
		
		if(dead)
			return;

		visibility = level.getLightIntensity(Math.round(x), Math.round(y));

		float newX = x;
		float newY = y;

		float playerStep = STEP;
		if (inputX != -1 && inputY != -1) {
			playerStep = (float) (playerStep * 0.707);
		}

		if(inputX == LEFT) {
			newX-=playerStep;
		} else if(inputX == RIGHT) {
			newX+=playerStep;
		}
		if(inputY == UP) {
			newY-=playerStep;
		} else if(inputY == DOWN) {
			newY+=playerStep;
		}

		float oldX = x;
		float oldY = y;

		this.x = newX;
		this.y = newY;

		if(level.collides(this)) {
			this.x = oldX;
			this.y = oldY;
		}

		if(sprinting){
			stamina -= STAMINA_COST;
			if(stamina <= 0){
				stamina = 0;
				setSprint(false);
			}
		}
	}

	public void kill() {
		dead = true;
		STEP = STANDARD_STEP;
		//TODO important
	}
	
	public boolean isDead(){
		return dead;
	}

	public void update(Level level) {
		drawable.update(this);
		
		if(level.playerAtExit())
			kill();

		visibility = level.getLightIntensity(Math.round(x), Math.round(y));
		if(visibility > 0f && stamina < 1.0f){
			stamina += (visibility * STAMINA_RECHARGE);
			if(stamina > 1.0f) stamina = 1.0f;
		}
	}

	public static final String DIR = Util.resources+"player"+File.separator;

	public static final int LEFT = Input.KEY_LEFT;
	public static final int RIGHT = Input.KEY_RIGHT;
	public static final int UP = Input.KEY_UP;
	public static final int DOWN = Input.KEY_DOWN;

	public static float STANDARD_STEP = 1f;
	public static float SPRINTING_STEP = 3f;
	public static float CROUCHING_STEP = 0.75f;

	public static float STEP = STANDARD_STEP;

	public float getX() {
		return x;
	}

	public float getY() {
		return y;
	}

}
